<template>
  <canvas :width="width" :height="height" ref="canvasRef"></canvas>
  <br />
  <div>{{ rotate }}</div>
  <br />
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
import * as GLMatrix from "gl-matrix";

const width = ref<number>(600);
const height = ref<number>(600);
const canvasRef = ref<HTMLCanvasElement>();
const glRef = ref<WebGLRenderingContext>();
const proRef = ref<WebGLProgram>();
const taskId = ref<number>()

onMounted(() => {
  init();
  taskQueue();
  rotate.value = 0;
});


const init = () => { // 顶点着色器  偏移量为屏幕坐标系
  const gl = canvasRef.value?.getContext("webgl");
  if (!gl) return;
  gl.viewport(0, 0, width.value, height.value);

  /***
    x’ = x * cos β - y * sin β
    y’ = x * sin β + y * cos β
    z’ =z
   */

  // const veString = `
  //   attribute vec4 a_position;
  //   attribute  float deg;
  //   uniform mat4 viewPro;
  //   void main(void){
  //     gl_Position = viewPro * a_position;
  //     gl_Position = vec4(
  //       gl_Position.x * cos(deg) - gl_Position.y*sin(deg),
  //       gl_Position.x * sin(deg) + gl_Position.y* cos(deg),
  //       gl_Position.z,
  //       1.0);
  //     gl_PointSize = 1.0;
  //   }
  // `;

  /**
   * 转化矩阵
  | cos(β) sin(β)  0 0 |
  | -sin(β) cos(β) 0 0 |
  | 0         0    1 0 |
  | 0         0    0 1 |
   
   */

  const veString = `
    attribute vec4 a_position;
    uniform mat4 tran;
    uniform mat4 viewPro;
    void main(void){
      gl_Position = viewPro * a_position * tran;
      gl_PointSize = 1.0;
    }
  `;



  const frString = `
    void main(void){
      gl_FragColor = vec4(1.0,1.0,0.0,1.0);
    }
  `;
  const veShader = gl.createShader(gl.VERTEX_SHADER);
  if (!veShader) return;
  gl.shaderSource(veShader, veString);
  gl.compileShader(veShader);

  if (!gl.getShaderParameter(veShader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(veShader) || "");
  }

  const frShader = gl.createShader(gl.FRAGMENT_SHADER);
  if (!frShader) return;
  gl.shaderSource(frShader, frString);
  gl.compileShader(frShader);

  const pro = gl.createProgram();
  if (!pro) return;
  gl.attachShader(pro, veShader);
  gl.attachShader(pro, frShader);
  gl.linkProgram(pro);
  gl.useProgram(pro);


  const mat4 = GLMatrix.mat4.create();
  GLMatrix.mat4.ortho(mat4, 0, width.value, height.value, 0, -1, 1);

  const view = gl.getUniformLocation(pro, "viewPro");
  gl.uniformMatrix4fv(view, false, mat4);


  const points = new Float32Array([150, 150, 450, 150, 450, 450, 150, 450]);
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);


  const a_position = gl.getAttribLocation(pro, "a_position");
  gl.enableVertexAttribArray(a_position);
  gl.vertexAttribPointer(a_position, 2, gl.FLOAT, true, 0, 0);



  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.drawArrays(gl.LINE_LOOP, 0, points.length / 2)

  glRef.value = gl;
  proRef.value = pro;
};

const rotate = ref<number>(0);
const taskQueue = () => {
  if (!glRef.value) return;
  if (!proRef.value) return;
  const gl = glRef.value;
  const pro = proRef.value;
  rotate.value = rotate.value + 0.005;
  if (rotate.value >= Math.PI * 2) {
    rotate.value = 0;
  }


  const tranDeg = gl.getAttribLocation(pro, 'deg');
  const tran = gl.getUniformLocation(pro, 'tran')
  // 打开顶点着色器即可注释即可
  if (tranDeg !== -1) {
    // 1:坐标转换
    gl.vertexAttrib1f(tranDeg, rotate.value)
  } else if (tran !== -1) {

    // 2:矩阵转换 4x4
    const mat = new Float32Array([
      Math.cos(rotate.value), Math.sin(rotate.value), 0.0, 0.0,
      -Math.sin(rotate.value), Math.cos(rotate.value), 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      0.0, 0.0, 0.0, 1.0,
    ]);
    gl.uniformMatrix4fv(tran, false, mat)
  }




  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.drawArrays(gl.LINE_LOOP, 0, 4)
  taskId.value = requestAnimationFrame(taskQueue)
}

const onRenderTriStart = () => {
  onRenderTriEnd();
  rotate.value = 0;
  taskId.value = requestAnimationFrame(taskQueue)
};

const onRenderTriEnd = () => {
  taskId.value && cancelAnimationFrame(taskId.value)
  taskId.value = 0;
}


</script>

<style></style>
